package draw.impl;

import java.util.Iterator;
import java.util.List;
import java.util.LinkedList;
import java.util.Collections;
import draw.spec.*;

/**
 * An Animation usually refers to a set of frames put together in a
 * timed sequence. This version of an animation generates frames given
 * two images; their start and their finish.
 *
 * @author Matthew B. Gray <matthew.b.gray@gmail.com
 * @version 1.0
 */
public class Animation implements Iterable {
	private List<AnimatedStroke> strokes;
	private Picture start, finish;
	private boolean underConstruction;

	public Iterator<AnimatedStroke> iterator() { return strokes.iterator(); }

	public Animation(Picture start, Picture finish) {
		//TODO: Choose a better implementation of this instead of LinkedList().
		this.strokes = new LinkedList<AnimatedStroke>();
		this.start = start;
		this.finish = finish;
		underConstruction = true;
	}

	public boolean LinkStroke(StaticStroke s, StaticStroke f)
			throws OperationNotSupportedException {

		if(!underConstruction)
			throw new OperationNotSupportedException("This Animation is not under construction");
		if(!this.start.contains(s) || !this.finish.contains(f))
			return false;

		return strokes.add(new AnimatedStroke(s,f));
	}

	/**
	 * Returns the stroke closest to that point.
	 * @param p Input point
	 * @return null if no such stroke near by. Otherwise reference to closest stroke.
	 */
	public StaticStroke getStroke(Point p) {
		// TODO: Implement me!
		return new StaticStroke();
	}

	/**
	 * Returns a picture object that represents that particular frame of time.
	 * @param time Parameter between 0 and 1.
	 * @return A picture representing the frame in given time slice.
	 * @throws OperationNotSupportedException
	 * @throws TimeException If time is not between 0 and 1
	 */
	public Picture getFrame(Double time)
			throws TimeException {
		Picture toReturn = new Picture();

		if(time.equals(0))
			toReturn = start;
		else if(time.equals(1))
			toReturn = finish;
		else
			for(AnimatedStroke stroke : strokes)
				toReturn.add(stroke.getState(time));

		return toReturn;
	}

	public void close()
			throws OperationNotSupportedException {

		if(!underConstruction)
			throw new OperationNotSupportedException
				("Animation has already been closed.");

		for(Object stroke : start)
			if(!((StaticStroke)stroke).isUsed())
				throw new OperationNotSupportedException
					("Haven't used all strokes in start");

		for(Object stroke : finish)
			if(!((StaticStroke)stroke).isUsed())
				throw new OperationNotSupportedException
					("Haven't used all strokes in finish");

		// If we get to this point it implies that all elements of start and finish are used.
		Collections.sort(strokes); // Sorts based on order strokes were created in start ^^.
		underConstruction=false;
	}
}
